/**
* project3D Engine
* @author John Sword
* @version 2 - AS3
* 
* simple Plane Primitive
*/

package engine.objects
{
	
	import engine.camera.Camera3D;
	import engine.geom.Point3D;
	import engine.geom.UV;
	import engine.geom.Vector;
	import engine.geom.Vertex;
	import engine.materials.Material;
	import engine.math.Matrix3x3;
	
	import flash.geom.Point;

	public class Billboard extends Object3D
	{
		
		private var h:Number;
		private var w:Number;
		// bounding box
		//private var bBox:Object;
		private static const max:Function 	= Math.max;
		private static const min:Function 	= Math.min;
		private static const sqrt:Function 	= Math.sqrt;
		
		/**
		* Constructor
		* @param h Height of the Box
		* @param d Depth of the Box
		* @param w Width of the Box
		* @param r Render mode
		*/
		public function Billboard ( m:Material, w:int, h:int )
		{
			this.h = (!w) ? 10 : w;
			this.w = (!h) ? 10 : h;
			this.position = new Vector();
			this.material = m;
			this.cull = false;
			build();
			
		}
		
		// initialization
		private function build () : void
		{
			// build vertexes
			createVertex(new Vertex (-w,-h,0));
			createVertex(new Vertex (w,-h,0));
			createVertex(new Vertex (-w,h,0));
			createVertex(new Vertex (w,h,0));
			
			createFace ( 2, 0, 1, new UV(1,0),new UV(1,1),new UV(0,1), material );
			createFace ( 1, 3, 2, new UV(0,1),new UV(0,0),new UV(1,0), material );
			
			// build faces (a Tri Poly box has 12 faces)
			//createFaceVertexCoords(0,2,3);
			//createFaceVertexCoords(3,1,0);
			
			// texture coordinates
			//createUV(0,2,3,[[1,0],[1,1],[0,1]]);
			//createUV(3,1,0,[[0,1],[0,0],[1,0]]);
			/*
			var i:Number = aFacesAssoVertex.length;
			while (i--)
			{
				var v1:Number = int(aFacesAssoVertex[i][0]);
				var v2:Number = int(aFacesAssoVertex[i][1]);
				var v3:Number = int(aFacesAssoVertex[i][2]);
				// for retrieving texture uvs from textures array
				var texVs:String = v1+","+v2+","+v3; // 3 vertices form a face
				// get uv coords for this face
				var texsUVs:Array = aFacesTextures[texVs];
				var a:Vertex = tVertices[aFacesAssoVertex[i][0]];
				var b:Vertex = tVertices[aFacesAssoVertex[i][1]];
				var c:Vertex = tVertices[aFacesAssoVertex[i][2]];
				//faces.push( new Face ( [ a, b, c ], material, texsUVs ) );
			}
			
			transform_vertices ( null );
			*/
		}
		
		public override function project ( cam:Camera3D, occlusion:Boolean = false ) : int
		{
			
			//var cm:Matrix3x3 = cam.getRotationMatrix();
			//rotMatrix.angleRotation( new Vector(45,45,45 ) );
			//rotMatrix.fromAngleAxis( 45, new Vector() );
			
			//return super.project( cam, false );
			
			var rme:Boolean = renderMe;
			var rcam:Boolean = cam.renderMe;
			
			renderMe = false;
			
			if ((!rme && !rcam) || !isVisible ) return 0;

			// get Camera parameters
			var m:Matrix3x3 = cam.getRotationMatrix();
			var camV:Vector = cam.getPosition();
			var camPosX:int = camV.x,
			camPosY:int = camV.y,
			camPosZ:int = camV.z,
			camEyeZ:int = cam.eyeZ, // also known as perspective or FOV
			camEyeX:int = cam.eyeX,
			camEyeY:int = cam.eyeY,
			zClipping:int = cam.zClipping,
			x:int,
			y:int,
			z:int,
			zcalc:int,
			visibleFaces:int = 0,
			w:int = cam.w,
			h:int = cam.h,
			rvx:int,
			rvy:int,
			rvz:int;	
			
			if ( rme ) 
			{
				//var rm:Matrix3x3 = update_rotation_matrix (); // get object transformed vertices
				var oVs:Array = oVertices; // non transformed object (original) vertices
				var xpos:int = X,
				ypos:int = Y,
				zpos:int = Z,
				vox:int,
				voy:int,
				voz:int;
				var sx:Number = scale.x,
				sy:Number = scale.y,
				sz:Number = scale.z;
			}
			
			var tvs:Array = tVertices; // current object vertices (transformed)
			var vtx:Vertex; // vertex obj for holding current vertex
			
			if ( occlusion ) resetOBB ();
			
			// transform each vertex and create screen coordinates
			var i:int = tvs.length
			while (--i > -1)
			{
				vtx = tvs[i] as Vertex;
				
				// apply transformations to a temporary vertex that is holding original vertex data
				if ( rme ) // only if needed 
				{	
					// points to the original vertex information
					// and applies scale
					vtx.x = vox = oVs[i].x * sx + xpos;
					vtx.y = voy = oVs[i].y * sy + ypos;
					vtx.z = voz = oVs[i].z * sz + zpos;
					// use rotation matrix to apply rotation transformations
					// & translate vertex to current object position
					//vtx.x = int((vox * rmaa + voy * rmab + voz * rmac) + xpos);
					//vtx.y = int((vox * rmba + voy * rmbb + voz * rmbc) + ypos); // Y goes down to conform with camera
					//vtx.z = int((vox * rmca + voy * rmcb + voz * rmcc) + zpos);	
				}
				
				// translate the point to the camera
				x = vtx.x - camPosX;
				y = vtx.y - camPosY;
				z = vtx.z - camPosZ;
				
				// apply camera rotation matrix
				rvx = x * m.aa + y * m.ab + z * m.ac;
				rvy = x * m.ba + y * m.bb + z * m.bc;
				rvz = x * m.ca + y * m.cb + z * m.cc;
				//rvx = x;
				//rvy = y;
				//rvz = z;
				
				// shift world to the camera to make it first person (the camera at your eye)
				z = rvz - camEyeZ;
			
				// check if vertex is visible
				//vtx.visible = ( z > -camEyeZ );
				vtx.visible = ( z > 0 );
				
				// only calculate screen coords for visible vertices
				if ( !vtx.visible )	continue;
	
				// convert to screen coordinates
				//vtx.screen.x = (camEyeX + (rvx * camEyeZ) / (z + camEyeZ)) >> 0;
				//vtx.screen.y = (camEyeY + (rvy * camEyeZ) / (z + camEyeZ)) >> 0;
				vtx.screen.x = int(camEyeX + (rvx * camEyeZ) / z);
				vtx.screen.y = int(camEyeY + (rvy * camEyeZ) / z);
				vtx.screen.z = z;
				
				// calculate bounding box/*
				if ( occlusion )
				{
					OBB.min.x = min( vtx.screen.x, OBB.min.x );
					OBB.max.x = max( vtx.screen.x, OBB.max.x );
					OBB.min.y = min( vtx.screen.y, OBB.min.y );
					OBB.max.y = max( vtx.screen.y, OBB.max.y );
					OBB.minz.z =  min( z, OBB.minz.z );
					OBB.maxz.z =  max( z, OBB.maxz.z );
				}
	
				++visibleFaces;
			}			
			
			// check if object has visible vertices which means faces can be rendered
			if (visibleFaces > 2)
			{
				facesVisible = true;
				// get distance to camera
				if ( occlusion ) {
					screenZ = distance( cam.getPosition() );
				}
				return 1;
			}

			return 0;
		}
		
		private function resetOBB () : void
		{
			OBB.min  = new Point(Infinity,Infinity);
			OBB.max  = new Point(-Infinity,-Infinity);
			OBB.maxz = new Point3D(1,1,-Infinity);
			OBB.minz = new Point3D(1,1,Infinity)
			//OBB.size = new Point(Infinity,Infinity);
		}
		
	}

	
}

